﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Hont.BlazingNodePackage
{
    public abstract class Node : INode
    {
        Vector2 mPosition;
        protected List<Port> mInPortList;
        protected List<Port> mOutPortList;
        protected Document mCurrentDocument;

        public long GUID { get; set; }
        public virtual string Category { get { return "Default"; } }
        public virtual string Name { get { return GetType().Name; } }

        public List<Port> InPortList { get { return mInPortList; } set { mInPortList = value; } }
        public List<Port> OutPortList { get { return mOutPortList; } set { mOutPortList = value; } }

        public Vector2 Position { get { return mPosition; } set { mPosition = value; } }
        public virtual Vector2 Size { get { return new Vector2(100, 40); } }

        [XmlIgnore]
        public virtual IParameter LinkedParameter { get; set; }

        public virtual object Context { get; set; }

        public string Remark { get; set; }

        [XmlIgnore]
        public Graph CurrentGraph { get; set; }
        [XmlIgnore]
        public Graph SubGraph { get; set; }


        public Node()
        {
            GUID = BlazingNodeHelper.CreateGUID();
        }

        protected virtual void Init()
        {
            mInPortList = new List<Port>();
            mOutPortList = new List<Port>();

            mInPortList.Add(new Port() { Name = "In", IsSpark = true, Host = this });
            mOutPortList.Add(new Port() { Name = "Out", IsSpark = true, Host = this });
        }

        /// <summary>
        /// Execute to after nodes.
        /// </summary>
        public virtual IEnumerator Execute(Port port)
        {
            for (int i = 0; i < mOutPortList.Count; i++)
            {
                if (!mOutPortList[i].IsSpark) continue;

                if (mOutPortList[i].ConnectPort != null)
                {
                    yield return mOutPortList[i].ConnectPort.Host.Execute(mOutPortList[i]);
                }
            }

            yield return true;
        }

        protected IEnumerator ExecutePort(Port port)
        {
            if (port.ConnectPort != null)
            {
                yield return port.ConnectPort.Host.Execute(port);
            }
        }

        protected IEnumerator LoopExecutePort(Port port)
        {
            while (true)
            {
                yield return ExecutePort(port);
                yield return null;
            }
        }

        /// <summary>
        /// Nothing do anything,please remove base class invoke.
        /// </summary>
        public virtual void OnDrawAttributesGUI(out bool updateUI)
        {
            updateUI = false;
        }

        public virtual object Clone()
        {
            var cloned = base.MemberwiseClone() as Node;

            cloned.GUID = BlazingNodeHelper.CreateGUID();
            cloned.mInPortList = new List<Port>();
            cloned.mOutPortList = new List<Port>();
            cloned.Init();

            return cloned;
        }

        /// <summary>
        /// Nothing do anything,please remove base class invoke.
        /// </summary>
        public virtual void OnDeserialize()
        {
        }

        /// <summary>
        /// Nothing do anything,please remove base class invoke.
        /// </summary>
        public virtual void OnEditorUpdate()
        {
        }

        /// <summary>
        /// Nothing do anything,please remove base class invoke.
        /// </summary>
        public virtual void OnAwake(Document document)
        {
            mCurrentDocument = document;
        }

        /// <summary>
        /// Nothing do anything,please remove base class invoke.
        /// </summary>
        public virtual void OnDestroy()
        {
        }
    }
}
